package com.example.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.config.CustomTransactionConfig;
import com.example.demo.config.wx.miniapp.WxMaProperties;
import com.example.demo.entity.DTO.UserLoginByWeChatDTO;
import com.example.demo.entity.User;
import com.example.demo.entity.Users;
import com.example.demo.mapper.UsersMapper;
import com.example.demo.service.IUsersService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author Mr.we
 * @since 2024-05-28
 */
@EqualsAndHashCode(callSuper = true)
@Service
@Data
@Slf4j
public class UsersServiceImpl extends ServiceImpl<UsersMapper, User> implements IUsersService {

    @Autowired
    private UsersMapper usersMapper;

    //    @Qualifier("customTransactionTemplate")//弄成理想的依赖包
    @Autowired
    private CustomTransactionConfig transactionTemplate;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private final RestTemplate restTemplate;

    @Resource
    private final StringRedisTemplate stringRedisTemplate;

    @Resource
    private final WxMaProperties wxMaProperties;

    @Override
    @Transactional
    public UserLoginByWeChatDTO wechatLogin(User users) {
        final UserLoginByWeChatDTO[] userLoginByWeChatDTO = {new UserLoginByWeChatDTO()};
        if (users.getOpenId() == null || users.getOpenId().isEmpty()) {
            // 处理open_id为空的情况，可能是抛出异常或返回错误信息
            throw new IllegalArgumentException("open_id cannot be null or empty");
        }
        // 对open_id进行简单的验证，实际中可能需要更复杂的逻辑
        if (!isValidOpenId(users.getOpenId())) {
            // 处理open_id无效的情况
            throw new IllegalArgumentException("Invalid open_id format");
        }
        try {
            // 使用事务确保数据一致性
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    User users1 = findUserByOpenId(users.getOpenId());
                    if (users1 != null) {
                        log.info(users1.getUserId()+":::users");
                        // 复制属性
                        BeanUtil.copyProperties(users1, userLoginByWeChatDTO[0]);
                    } else {
                        // 保存用户
                        saveUser(users);
                        // 再次查询并返回
                        userLoginByWeChatDTO[0] = wechatLogin(users); // 这里不再递归调用，而是重新查询
                    }
                }
            });
        } catch (Exception e) {
            // 处理可能的异常，例如数据访问异常
            // 记录日志、抛出自定义异常或返回错误信息等
            throw new RuntimeException("Error during wechat login", e);
        }
        return userLoginByWeChatDTO[0];
}

    private boolean isValidOpenId(String openId) {
        // 实现open_id的格式验证逻辑，这里仅为示例
        return openId.matches("^[a-zA-Z0-9]+$");
    }

    /**
     * 根据OpenId查找用户信息。
     *
     * @param openId 用户的OpenId，用于唯一标识一个用户。
     * @return Users 用户对象。如果找到了匹配的用户，则返回该用户对象；如果没有找到，则返回null。
     */
    @Override
    public User findUserByOpenId(String openId) {
        // 使用QueryWrapper构造查询条件，查询open_id字段等于openId的用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("open_id", openId);
        return usersMapper.selectOne(queryWrapper); // 执行查询并返回结果
    }

    /**
     * 保存用户信息到数据库。
     *
     * @param users 用户信息对象，包含用户的所有相关数据。
     *              该方法会将用户信息插入到数据库中，如果该用户之前不存在的话。
     */
    @Override
    public void saveUser(User users) {
        usersMapper.insert(users); // 调用Mapper接口，将用户对象插入数据库
    }


    @Override
    @Transactional
    public boolean register(User users) {
        boolean result = usersMapper.register(users);
        return !result;
    }


    /**
     * 通过微信小程序的code换取用户的OpenId
     *
     * @param code 由微信小程序授权时获取的code，用于向微信服务器换取用户OpenId
     * @return 返回从微信服务器获取到的用户OpenId
     * @throws RuntimeException 如果无法从微信服务器获取OpenId，则抛出异常
     */
    @Override
    public String getOpenId(String code) {
        // 构建向微信服务器发送请求的URL
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxMaProperties.getConfigs() + "&secret=" + "SECRET" + "&js_code=" + code + "&grant_type=authorization_code";

        // 向微信服务器发送请求，获取响应
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

        // 判断请求是否成功
        if (response.getStatusCode() == HttpStatus.OK) {
            // 解析响应的JSON对象
            JsonObject jsonObject = JsonParser.parseString(response.getBody()).getAsJsonObject();

            // 检查JSON对象中是否包含openid字段
            if (jsonObject.has("openid")) {
                // 从JSON对象中获取openid，并存储到Redis中
                String openid = jsonObject.get("openid").getAsString();
                stringRedisTemplate.opsForValue().set("openid:" + code, openid);

                // 返回获取到的openid
                return openid;
            }
        }
        // 如果无法正常获取openid，则抛出运行时异常
        throw new RuntimeException("Failed to get openid from WeChat");
    }

}
